from rest_framework.views import APIView
from rest_framework.response import Response
from personapp.views import MyTokenAuth
import redis
from .sers import *
from .utils import OrderSN
import decimal
from django.db import transaction

# 使用连接池 优化方案 完成 redis的操作
pool = redis.ConnectionPool(host='localhost', port=6379, decode_responses=True)
# 使用连接池，从连接池中 获取一个连接
r = redis.Redis(connection_pool=pool)


# 添加购物车到redis中

class CartView(APIView):

    def get(self, request):
        user = request.user
        print("user_cart:", user)
        cart_dic = r.hgetall("cart_%s" % user.id)

        # 根据 商品的id去 获取商品的信息
        cart_list = []
        for gid, num in cart_dic.items():
            cart = {}
            goods = Goods.objects.get(id=gid)
            cart["gid"] = goods.id
            cart["name"] = goods.name
            cart["price"] = goods.price
            cart["pic"] = "http://127.0.0.1:8000" + goods.pic.url
            cart["num"] = int(num)
            cart["stock"] = goods.stock

            cart_list.append(cart)
        # 获取 选中的所有购物记录
        select_list = r.smembers("select_%d" % user.id)
        return Response({
            "cart_list": cart_list,
            "select_list": select_list
        })

    def post(self, request):
        # 添加购物车
        user = request.user
        gid = request.data.get('goods')
        num = request.data.get("num")

        # 增量值添加
        r.hincrby("cart_%d" % user.id, gid, num)

        return Response({"msg": "添加成功"})

    def put(self, request):
        user = request.user
        gid = request.data.get("cart")
        num = request.data.get("num")
        # 购物车的 商品选择 总个数改变 进行重新赋值
        r.hset("cart_%d" % user.id, gid, num)

        return Response({"msg": "修改成功"})

    def patch(self, request):
        # 部分更新
        user = request.user
        # 修改 选择的购物记录
        # 这里使用集合来保存，一个用户 选择了哪些 购物记录 select_uid:{gid1,gid2,gid3}
        gids = request.data.get("gids")

        # 先删除
        r.delete("select_%d" % user.id)
        # 在添加
        r.sadd("select_%d" % user.id, *gids)

        return Response({"msg": "习惯优秀", "code": 200})


class PlaceOrderView(APIView):
    def get(self, request):
        # 获取 该用户下 所有选中的购物记录
        user = request.user
        # 获取 选中的所有购物记录
        select_list = r.smembers("select_%d" % user.id)
        # 获取出所有的 商品信息
        queryset = Goods.objects.filter(id__in=select_list)

        # 获取 购物记录的个数
        gid_num_dic = r.hgetall("cart_%d" % user.id)
        cart_list = []
        for goods in queryset:
            temp = {
                "goods": GoodsListSer(goods).data,
                "num": gid_num_dic[str(goods.id)]
            }
            cart_list.append(temp)
        return Response(cart_list)


# 编写 订单接口
import time


class OrderView(APIView):

    def get(self, request):
        # 获取用户
        user = request.user
        # 根据用户获取订单
        queryset = Order.objects.filter(user_id=user.id)
        # 序列化
        ser = OrderListSer(queryset, many=True)
        return Response(ser.data)

    def post(self, request):
        # 反序列化实现 订单的添加
        sn = OrderSN.make_sn()

        # 计算总金额  不从前端传递，计算出 购物车中的总金额
        user = request.user
        gid_num_dict = r.hgetall("cart_%d" % user.id)
        total = 0
        for gid, num in gid_num_dict.items():
            # 判断是否在 集合中，如果在就 计算 不在就不计算
            if r.sismember("select_%d" % user.id, gid):  # 在里面 返回true
                price = Goods.objects.get(id=gid).price
                total += price * decimal.Decimal(num)

        request.data["sn"] = sn
        request.data["total"] = total
        request.data["user"] = user.id
        ser = OrderSer(data=request.data)
        if ser.is_valid():
            try:
                with transaction.atomic():
                    order = ser.save()  # 会给我们返回一个订单对象

                    #  在这里完成 订单项的添加
                    #  先 遍历所有的购物车，然后 找到选中的购物信息， 在添加到订单项

                    for gid, num in gid_num_dict.items():

                        if r.sismember("select_%d" % user.id, gid):

                            OrderItem.objects.create(order_id=order.id, num=num, goods_id=gid)

                            # 应该查看库存， 是否满足我们的num需要
                            # 枷锁  没有锁不让继续往下走
                            print("开始获取商品")
                            while True:
                                goods = Goods.objects.filter(id=gid).first()
                                print("商品:" + goods.name, "库存:", goods.stock)
                                time.sleep(2)
                                print("休眠结束")

                                if goods.stock < int(num):
                                    raise serializers.ValidationError(detail="库存不够，请重新下单")

                                # 修改 商品的库存与 销量
                                # goods.stock -= int(num)
                                # goods.sale += int(num)
                                # goods.save()
                                goods1 = Goods.objects.filter(id=gid, stock=goods.stock).first()
                                if goods1:
                                    goods1.stock -= int(num)
                                    goods1.sale += int(num)
                                    goods1.save()
                                    break
                                else:
                                    continue
                            # 删除下单的购物车
            except Exception as e:
                print(e)
                # 回滚
                transaction.rollback()
                return Response({"msg": "下单出错", "code": 400})
            # 没有错误 则提交
            transaction.commit()
            return Response({"msg": "下单成功", "code": 200, "sn": sn, "total": total})
        else:
            print(ser.errors)
            return Response({"msg": "下单失败", "code": 400})


# 开发一个支付接口
from alipay import AliPay
from alipay.utils import AliPayConfig


class AlipayView(APIView):

    def post(self, request):
        sn = request.data.get("sn")
        total = request.data.get("total")

        app_private_key_string = open("buyapp/alipay/app_private_key.txt").read()
        alipay_public_key_string = open("buyapp/alipay/alipay_public_key.txt").read()

        alipay = AliPay(
            appid="2016101600696807",
            app_notify_url=None,  # 默认回调url
            app_private_key_string=app_private_key_string,
            # 支付宝的公钥，验证支付宝回传消息使用，不是你自己的公钥,
            alipay_public_key_string=alipay_public_key_string,
            sign_type="RSA2",  # RSA 或者 RSA2
            debug=True,  # 默认False
            config=AliPayConfig(timeout=15)  # 可选, 请求超时时间
        )

        # 如果你是 Python 3的用户，使用默认的字符串即可
        subject = "美多商城订单支付"

        # 电脑网站支付，需要跳转到https://openapi.alipay.com/gateway.do? + order_string
        order_string = alipay.api_alipay_trade_page_pay(
            out_trade_no=sn,  # 订单号
            total_amount=total,  # 总金额
            subject=subject,  # 标题
            return_url="http://localhost:8000/api/v1/buy/pay_callback",
            # notify_url="https://example.com/notify"  # 可选, 不填则使用默认notify url
        )

        # 生成一个支付超链接，返回给vue端， 点击就激活这个超链接
        url = "https://openapi.alipaydev.com/gateway.do?" + order_string
        return Response({"url": url})


from django.views import View
from django.shortcuts import redirect


class AliPayBackView(View):

    def get(self, request):
        user = request.user
        # 获取回调的信息
        # 获取 订单号
        sn = request.GET.get("out_trade_no")
        #  获取 支付宝交易号
        trade_no = request.GET.get("trade_no")
        print("sn:", sn)
        print("trade_no:", trade_no)
        # 找到这个订单 并更新状态
        # 修改了  订单状态  并添加了 支付宝交易号
        Order.objects.filter(sn=sn).update(trade_no=trade_no, status=2)
        #  删除我们购物车中的 已经支付成功的购物信息
        print(user)
        # 查询所有的选中 然后删除
        gid_set = r.smembers("select_%d" % user.id)
        print("gid_set:", gid_set)
        for gid in gid_set:
            r.hdel("cart_%d" % user.id, gid)

        return redirect("http://127.0.0.1:8080/#/paysuccess?trade_no=" + trade_no)
